package com.cicadasmall.exception;

import com.cicadasmall.common.constant.Constant;
import com.cicadasmall.common.exception.ServiceException;
import com.cicadasmall.common.resp.R;
import com.cicadasmall.common.utils.SpringContextUtils;
import com.cicadasmall.logger.constant.LogTypeEnum;
import com.cicadasmall.logger.event.LogEvent;
import com.cicadasmall.logger.utils.LogUtils;
import com.cicadasmall.data.domain.LogDO;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.Objects;

/**
 * 全局异常处理器
 *
 * @author Jin
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Throwable.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R exception(Throwable throwable) {
        LogDO logDO = LogUtils.buildSysLog(LogTypeEnum.错误日志);
        logDO.setTitle(throwable.toString());
        logDO.setException(throwable.getMessage());
        SpringContextUtils.publishEvent(new LogEvent(logDO));
        throwable.printStackTrace();
        return R.error().setMessage(throwable.getMessage());
    }

    @ExceptionHandler({BadCredentialsException.class})
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public R badCredentialsException() {
        return R.newBuilder().code(Constant.ERROR_CODE).message("账号或密码错误！").build();
    }

    @ExceptionHandler({UnapprovedClientAuthenticationException.class})
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public R unapprovedClientAuthenticationException(UnapprovedClientAuthenticationException exception) {
        return R.newBuilder().code(Constant.ERROR_CODE).message(exception.getMessage()).build();
    }

    @ExceptionHandler({IllegalArgumentException.class, ServiceException.class, BindException.class})
    @ResponseStatus(HttpStatus.OK)
    public R illegalArgumentException(Exception exception) {
        if (exception instanceof BindException) {
            BindException bindException = (BindException) exception;
            return R.newBuilder().
                    code(Constant.ERROR_CODE).
                    message(Objects.requireNonNull(bindException.getFieldError()).getDefaultMessage().concat(" [ " + bindException.getFieldError().getField() + " ]")).
                    build();
        }
        return R.newBuilder().code(Constant.ERROR_CODE).message(exception.getMessage()).build();
    }

    @ExceptionHandler({AccessDeniedException.class})
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public R accessDeniedException(AccessDeniedException accessDeniedException) {
        return R.newBuilder().code(Constant.ERROR_CODE).message(accessDeniedException.getMessage()).build();
    }

}
